#ifndef MEMORYMANAGER_H
#define MEMORYMANAGER_H

#include "BitOps.h"
#include "Testing.h"

#ifndef NULL
#define NULL 0						/* NULL, we bow down and worship you. */
#endif
#define RAM_SIZE 1048576			/* The size of RAM in bytes. */
#define BS_SIZE 67108864			/* The size of BACKING STORE in bytes. */
#define FRAME_SIZE 4096				/* The size of a frame in bytes. */
#define NUM_SYSTEM_FRAMES 56		/* The number of system frames set aside for the OS. */
#define NUM_PAGETABLES 100			/* The max number of page tables allowed by the OS. */


/**
 * PageTable which refrences logical page numbers to physical page numbers.
 * Each row is split into sections, a 14 bit physical page number, and a 2 bit validity
 * variable for defragmenting.
 */
typedef struct PageTable_s{
	unsigned short int row[BS_SIZE/FRAME_SIZE];	/* The rows of the table (Contain an 8bit validity/frame address). */
	int nextAvailableIndex;						/* The next free index. */
	int freeRows;								/* The total number of rows remaining in the table (Gaps included). */
	int freeEndRows;							/* The number of rows left at the end of the table. */
}PageTable;


/**
 * MetaTable which maps PageTableIDs to logical page numbers.
 * index [n][0] stores the starting page, index [n][1] stores the 
 * ending page (inclusive).
 */
typedef struct MetaTable_s{
	unsigned short int row[NUM_PAGETABLES][2];
	int freeRows;
}MetaTable;


/**
 * SwapTable which maps frames in RAM to physical pages in backing store.
 */
typedef struct SwapTable_s{
	unsigned short int row[(RAM_SIZE/FRAME_SIZE)-NUM_SYSTEM_FRAMES];
}SwapTable;


extern PageTable pageTable;
extern MetaTable metaTable;
extern SwapTable swapTable;


/**
 * Allocates the specified number of pages and records them in the MetaTable.
 * @author Daniel Fairweather, Ying Wang
 * @param numberOfPages The number of pages to be allocated.
 * @returns >= 0 The id of the MetaTable entry (PageTableID)
 *			-1 The user requested 0 or negative number of pages.
 *			-2 Not enough pages in backing store.
 *			-3 No remaining page tables (Reached limit of NUM_PAGETABLES)
 */
int allocateFrames(int numberOfPages);


/**
 * Deallocates the rows within the specified page table.
 * @author Daniel Fairweather, Ying Wang
 * @param pageTableID The page table in which to clear.
 * @returns  0 If all pages were removed.
 *          -1 If the page table is invalid.
 */
int deallocateTable(int pageTableID);


/**
 * Brings all of the rows within the page table to the top, freeing space at the end of the table.
 * @author Daniel Fairweather
 */
void squishPageTable();


int getSmallestIndex(int above);


/**
 * Initalizes the structures necessary for memory management.
 * @author Daniel Fairweather
 */
void init();

/**
 * Simulates a page fault. Removes a frame from swap space and puts the new one in.
 * Note: Uses sequential replacement for now.
 * @author Daniel Fairweather
 * @param pageTableID The page table to remove from.
 * @param pageNum The logical page number within the page table.
 * @returns  0 If success.
 *			-1 If the page is already in RAM.
 *			-2 If the page doesn't belong to the page table.
 */
int pageFault(int pageTableID, int pageNum);



/**
 * Simulates a page reference. If the page is in RAM, update the LRU Queue to reflect the reference.
 * Otherwise, call pageFault().
 * @author Ying Wang
 * @param pageTableID The page table where the page should be in.
 * @param pageNum The logical page number within the page table.
 * @returns  0 If success and a page fault occured.
 *           1 If success.
 *			-2 If the page doesn't belong to the page table.
 */
int access(int pageTableID, int pageNum);



int is_in_swaptable(short unsigned int address);

#endif